import { _decorator, Component, director, instantiate, Node, Prefab, SpriteFrame } from 'cc';
import DataManager from '../Global/DataManager';
import { JoyStickManager } from '../UI/JoyStickManager';
import { ResourceManager } from '../Global/ResourceManager';
import { ActorManager } from '../Entity/Actor/ActorManager';
import { EventEnum, PrefabPathEnum, SceneEnum, TexturePathEnum } from '../Enum';
import { ApiMsgEnum, EntityTypeEnum, IClientInput, InputTypeEnum } from '../Common';
import { BulletManager } from '../Entity/Bullet/BulletManager';
import { ObjectPoolManager } from '../Global/ObjectPoolManager';
import { NetWorkManager } from '../Global/NetWorkManager';
import EventManager from '../Global/EventManager';
import { IMsgClientSync, IMsgServerSync } from '../Common/Msg';
import { deepClone } from '../Utils';
const { ccclass, property } = _decorator;

@ccclass('BattleManager')
export class BattleManager extends Component {
    private stage:Node 
    private ui:Node
    private pendingMsg:IMsgClientSync[]=[]
    private shouldUpdate=false
    protected onLoad(): void {
        
        
    }

    //在update生命周期函数的执行是不会等其中的异步函数应用的，可能会导致不断执行异步函数，
    // 所以不能在update中进行实例化，要把资源提前在start里加载好
    async start() {
        //网络连接之前调用clearGame
        this.clearGame()
        //加载资源和连接服务器没有耦合关系所以可以用promise.all并行执行
        await Promise.all([this.connectServer(),this.loadRes()])
        //资源加载完成后初始化服务器
        this.initGame()

        //绑定网络监听事件
        EventManager.Instance.on(EventEnum.ClientSync,this.handleClientSync,this)
        //绑定游戏结束事件
        EventManager.Instance.on(EventEnum.GameEnd,this.handleGameEnd,this)
        //监听服务端信息
        NetWorkManager.Instance.listenMsg(ApiMsgEnum.MsgServerSync,this.handleServerSync,this)
        NetWorkManager.Instance.listenMsg(ApiMsgEnum.MsgGameEnd,this.listenGameEnd,this)
        
    }
    //初始化赋值放到initgame
    initGame(){
        this.initJoyStick();
        this.initShoot();
        this.initMap()
        this.shouldUpdate=true
        
    }
    /**
     * 初始化方向盘
     */
    initJoyStick(){
        const prefab =DataManager.Instance.prefabMap.get(EntityTypeEnum.JoyStick)
        const joyStick = instantiate(prefab)
        joyStick.setParent(this.ui)
        //获取JoyStickManager脚本
        DataManager.Instance.jm =  joyStick.getComponent(JoyStickManager)
        const jm = joyStick.getComponent(JoyStickManager)
        jm.init()
        
    }
    /**
     * 初始化射击按钮
     */
    initShoot(){
        const prefab = DataManager.Instance.prefabMap.get(EntityTypeEnum.Shoot)
        const shoot = instantiate(prefab)
        shoot.setParent(this.ui)
        
    }
    /**
     * 销毁逻辑放到clearGame中
     */
    clearGame(){
        //解绑网络监听事件
        EventManager.Instance.off(EventEnum.ClientSync,this.handleClientSync,this)
        EventManager.Instance.off(EventEnum.GameEnd,this.handleGameEnd,this)
        NetWorkManager.Instance.unlistenMsg(ApiMsgEnum.MsgServerSync,this.handleServerSync,this)
        NetWorkManager.Instance.unlistenMsg(ApiMsgEnum.MsgGameEnd,this.listenGameEnd,this)
        //重置数据
        this.shouldUpdate=false
        ObjectPoolManager.Instance.reset();
        DataManager.Instance.reset();
        //重置节点
        DataManager.Instance.stage=this.stage = this.node.getChildByName("Stage")
        this.stage.destroyAllChildren()
        this.ui = this.node.getChildByName("UI")
        this.ui.destroyAllChildren()       
    }
    /**
     * 连接服务器
     */
    async connectServer(){
        // 尝试连接服务器，如果连接失败则递归重试
        if(!await  NetWorkManager.Instance.connect().catch(()=>false)){
            //递归调用自身，每隔一秒连接一次
            await new Promise((rs)=>setTimeout(rs,1000))
            await this.connectServer()
        }       
    }
    //加载资源
    async loadRes(){
        const list =[]
        //加载预制体
        for (const type in PrefabPathEnum) {
            const p=ResourceManager.Instance.loadRes(PrefabPathEnum[type],Prefab).then((prefab)=>{
                //将加载的prefab放入prefabMap中
                DataManager.Instance.prefabMap.set(type,prefab)
            })  
            list.push(p)
        }
        //加载图片
        for (const type in TexturePathEnum) {
            const p=ResourceManager.Instance.loadDir(TexturePathEnum[type],SpriteFrame).then((spriteFrames)=>{
                //将加载的texture放入textureMap中
                DataManager.Instance.textureMap.set(type,spriteFrames)
            })  
            list.push(p)
        }
        //它会等待所有的Promise对象完成，然后将它们的结果收集起来，按照传入的顺序放入一个数组中
        await Promise.all(list)
        
    }
    /**
     * 初始化地图
     */
    initMap(){
        const prefab= DataManager.Instance.prefabMap.get(EntityTypeEnum.Map)
        const map=instantiate(prefab)
        map.setParent(this.stage)
    }

    update(dt){
        //在start生命周期中也不能保证全部资源都加载完毕，所以需要在这里进行判断保证资源加载完毕才执行update
        if(!this.shouldUpdate){
            return
        }
        this.render()
        this.tick(dt)
    }


    tick(dt){
        this.tickActor(dt)
        //时间流逝的输入
        // DataManager.Instance.applyInput({
        //     type:InputTypeEnum.TimePast,
        //     //两次时间流逝的时间差
        //     dt,
        // })  
    }
    /**
     * 更新玩家位置
     */
    tickActor(dt){
        for (const data of DataManager.Instance.state.actors) {
            const {id}=data
            let am=DataManager.Instance.actorMap.get(id)
            //更新玩家位置信息
            am.tick(dt)
        }
    }

    render(){
        this.renderPlayer()
        this.renderBullet()
    }
    async renderPlayer(){
        //从datamanager的state中获取所有actor
        for (const data of DataManager.Instance.state.actors) {
            const {id,type}=data
            // console.log("玩家数据",data)
            let actorManager=DataManager.Instance.actorMap.get(id)
            //如果不存在，则创建
            if(!actorManager){
                const prefab= DataManager.Instance.prefabMap.get(type)
                
                if (!prefab) {
                    console.error(`Prefab 类型 ${type} 未预加载`);
                    continue;
                }
                const actor=instantiate(prefab)
                actor.setParent(this.stage)
                actorManager =actor.addComponent(ActorManager)
                DataManager.Instance.actorMap.set(id,actorManager)
                //初始化
                actorManager.init(data)
            }else{
                //如果存在则调用其渲染方法
                actorManager.render(data)
            }
        }
    }

    renderBullet(){
        //从datamanager的state中获取所有bullet
        for (const data of DataManager.Instance.state.bullets) {
            const {id,type}=data
            let bm=DataManager.Instance.bulletMap.get(id)
            //如果不存在，则创建
            if(!bm){
                const prefab= DataManager.Instance.prefabMap.get(type)     
                if (!prefab) {
                    console.error(`Prefab 类型 ${type} 未预加载`);
                    continue;
                }
                // const bullet=instantiate(prefab)
                const bullet=ObjectPoolManager.Instance.get(type)
                // bullet.setParent(this.stage)对象池中设置了父节点所以不用设置了
                //因为节点是从对象池拿的，所以不一定要addComponent，先getComponent看看有没有挂载脚本
                bm =bullet.getComponent(BulletManager)||bullet.addComponent(BulletManager)
                DataManager.Instance.bulletMap.set(data.id,bm)
                //初始化
                bm.init(data)              
            }else{
                //如果存在则调用其渲染方法
                bm.render(data)
            }
        }
    }
    /**
     * 处理客户端同步
     * @param input 
     */
    handleClientSync(input:IClientInput){
        DataManager.Instance.state = DataManager.Instance.lastState
        const msg = {
            input,
            //帧id每次发送让其自增
            frameId:DataManager.Instance.frameId++,
        }
        //发送消息，名称是MsgClientSync，数据是msg
        NetWorkManager.Instance.sendMsg(ApiMsgEnum.MsgClientSync,msg)
        // //注释掉预测回滚，不让本地进行预测输入，因为会导致本地的移动不同步，有bug
        // if(input.type ===InputTypeEnum.ActorMove){     
        // //把input应用到本地做预测输入（只做了ActorMove类型的input的预测输入）
        //     DataManager.Instance.applyInput(input)
        // //保存预测输入的input
        //     this.pendingMsg.push(msg)
        // }
    }
    /**
     * 处理服务端，注释掉了预测回滚
     */
    handleServerSync({inputs,lastFrameId}:IMsgServerSync){
        // 将当前状态重置为上一帧的状态
        // DataManager.Instance.state = DataManager.Instance.lastState
        // 遍历服务端发送的输入数据，应用每个输入
        for (const input of inputs) {
            //遍历inputs,调用applyInput方法
            DataManager.Instance.applyInput(input)
        }
        // // 将当前状态保存为上一帧状态（深拷贝）
        // DataManager.Instance.lastState = deepClone(DataManager.Instance.state)

        // // // 过滤掉已经处理过的消息（frameId <= lastframeId的消息）
        // this.pendingMsg = this.pendingMsg.filter((msg) => msg.frameId > lastFrameId)
        // // // 处理剩余的待处理消息
        // for (const msg of this.pendingMsg) {
        //     //遍历inputs,调用applyInput方法
        //     DataManager.Instance.applyInput(msg.input)
        // }
    }
    /**
     * 处理游戏结束
     */
    handleGameEnd(){
        NetWorkManager.Instance.callApi(ApiMsgEnum.ApiGameEnd,{rid:DataManager.Instance.roomInfo.id})
    }

    listenGameEnd(){
        this.clearGame()
        director.loadScene(SceneEnum.Hall)
    }
}

